



/**
 * This is main class file to implement mapping of the multiplication in CFU array
 * This class inherits FIR_mappping because basic mapping functionalities are same.  
 * 
 * 
 * @author kpatel
 *
 */

//Matrix Data Loading Methods

//CFUs Configuration Method

//CFUs Execution Method

//Statistics and Output Methods




public class Matrix_Multiplication_4x4_4channels_Mapping extends Matrix_Multiplication_Mapping implements Interface_Matrix_Multiplication_Mapping
{
	
	public int Channel_no = 1;
	

	@Override
	public void Configure_CFUs() 
	{
		// TODO Auto-generated method stub

		int cfu_row_index = 0, cfu_column_index = 0;

		/* 
		 * Configure all CFUs for MAC operations. The first operation will be 
		 * multiplication but as we have MAC unit so we are going to configure 
		 * all CFUs for MAC operations.
		 * 
		 */

		// As we are going to execute MAC operation on all the CFUs, we will comment out
		//the following for loop and simply configure all the CFUs for MAC operation.
		//for (int channelNo = 0; channelNo < no_channels_int; channelNo++) 
		
		{
			for (cfu_row_index = 0; cfu_row_index < no_cfu_row_int; cfu_row_index++ ) 
			{
				for(cfu_column_index = 0; cfu_column_index < no_cfu_column_int; cfu_column_index++)
				{
					Cfu_Array[cfu_row_index][cfu_column_index].Cfu_initialize(
							Cfu.Instruction_List.MAC, 0, 1, 2, 3, 4, 0,0xFFFF);
					// System.out.println("Cfu_Array [" + cfu_row_index + "][" +
					// (cfu_column_index) + "] Intialized");
				}
			}
		}
	}


	/*
	 * (non-Javadoc)
	 * @see Interface_Matrix_Multiplication_Mapping#Load_Data_into_CFUs()
	 * Please, refer to excel sheet for information about data loading in CFU arrays.
	 */

	@Override
	public void Load_FirstMatrix_Data_into_CFUs()
	{
		/*
		 * Note: Channels are mapped vertically
		 */

		/*
		 * It is assumed that two matrix are stored on by one in the RAM 
		 * 
		 */
		//ram_read_index = last_ram_read_index;
		int cfu_row_index = 0, cfu_column_index = 0;
		//for (int channelNo=0;channelNo<no_channels_int; channelNo++)

		{
			//We have assumed that matrix is square
			for (int cfuNo = 0; cfuNo < Size_of_Matrix * Size_of_Matrix; cfuNo++)
			{
				if (cfu_row_index == (no_cfu_row_int)) {
					// Move to next column
					cfu_column_index++;
					// Start from the first row of the next column
					cfu_row_index = 0;

				} 
				Cfu_Array[cfu_row_index][cfu_column_index].update_register(
						0, Matrix_Multiplication_RAM.ram[ram_read_index]);

				// increase column index and move forward to next CFU
				cfu_row_index++;

				// Read next data from RAM
				ram_read_index++;
				Matrix_Multiplication_RAM.RAM_accesses++;
			}
			
			
		}
		last_ram_read_index = ram_read_index;
	}


	@Override
	public void Load_SecondMatrix_Data_into_CFUs() 
	{
		ram_read_index = last_ram_read_index;
		int cfu_row_index = 0, cfu_column_index = 0;
		//		for (cfu_row_index=0;cfu_row_index<no_cfu_row_int; cfu_row_index++)
		//		{
		//			if(cfu_row_index == Size_of_Matrix)
		//			{
		//				ram_read_index = last_ram_read_index;
		//			}
		//		}
		for (int cfuNo = 0; cfuNo < Size_of_Matrix; cfuNo++) 
		{
//			if ((cfu_row_index % Size_of_Matrix)== 0) 
//			{
//				// Move to next row
//				ram_read_index++;
//				Matrix_Multiplication_RAM.RAM_accesses++;
//				// Start from the first column of the next row
//
//			} 
//			if(cfu_row_index == no_cfu_row_int)
//			{
//				cfu_column_index++;
//				cfu_row_index = 0;
//			}
			
			Cfu_Array[cfu_row_index][Channel_no-1].update_register(
					1, Matrix_Multiplication_RAM.ram[ram_read_index]);
			Matrix_Multiplication_RAM.RAM_accesses++;
			Cfu_Array[cfu_row_index][Channel_no].update_register(
					1, Matrix_Multiplication_RAM.ram[ram_read_index]);
			Matrix_Multiplication_RAM.RAM_accesses++;
			Cfu_Array[cfu_row_index+Size_of_Matrix][Channel_no-1].update_register(
					1, Matrix_Multiplication_RAM.ram[ram_read_index]);
			Matrix_Multiplication_RAM.RAM_accesses++;
			Cfu_Array[cfu_row_index+Size_of_Matrix][Channel_no].update_register(
					1, Matrix_Multiplication_RAM.ram[ram_read_index]);
			Matrix_Multiplication_RAM.RAM_accesses++;

			// increase column index and move forward to next CFU
			cfu_row_index++;

			// Read next data from RAM
			ram_read_index++;

		}
		
		last_ram_read_index = ram_read_index;
	}


	@Override
	public void Run_CFUs() {

		Configure_CFUs();

		// Loading filter coefficients

		last_ram_read_index = 0;
		
//		//RAM check
//		for(int i=0;i<Matrix_Multiplication_RAM.ram_array_index;i++)
//			
//			System.out.println("ram["+ i + "]="+ Matrix_Multiplication_RAM.ram[i]);
//		//===========================
		
		Load_FirstMatrix_Data_into_CFUs();


		int Cycle = 0;
		//===============================
		/*
		 * Remember we have to call Load_SecondMatrix_Data_into_CFUs method four times to get 
		 * all results. Please see the excel sheet/figure for more clear understanding. 
		 * 
		 */
		//===================================

		for (int x=0;x<Size_of_Matrix;x++)
		{
			Cycle = 1;
			Channel_no = 1;
			Load_SecondMatrix_Data_into_CFUs();
			//Four CFUs can be run in the first cycle
			Cfu_Array[Cycle-1][Channel_no-1].start_CFU();
			Cfu_Array[Cycle-1][Channel_no].start_CFU();
			Cfu_Array[(Cycle-1)+ Size_of_Matrix][Channel_no-1].start_CFU();
			Cfu_Array[(Cycle-1)+Size_of_Matrix][Channel_no].start_CFU();


			//==============================================
			for (Cycle = 2;Cycle <= Size_of_Matrix;Cycle++)
			{

				Cfu_Array[Cycle-1][Channel_no-1].update_register(2,
						Cfu_Array[Cycle-2][Channel_no-1].register_array[4]);
				Cfu_Array[Cycle-1][Channel_no].update_register(2,
						Cfu_Array[Cycle-2][Channel_no].register_array[4]);
				Cfu_Array[(Cycle-1)+ Size_of_Matrix][Channel_no-1].update_register(2,
						Cfu_Array[(Cycle-2)+ Size_of_Matrix][Channel_no-1].register_array[4]);
				Cfu_Array[(Cycle-1)+Size_of_Matrix][Channel_no].update_register(2,
						Cfu_Array[(Cycle-2)+Size_of_Matrix][Channel_no].register_array[4]);

//				if (Cycle == 4)
//					Bitwidth_Manipulation.final_result = true;
				
				Cfu_Array[Cycle-1][Channel_no-1].start_CFU();
				Cfu_Array[Cycle-1][Channel_no].start_CFU();
				Cfu_Array[(Cycle-1)+ Size_of_Matrix][Channel_no-1].start_CFU();
				Cfu_Array[(Cycle-1)+Size_of_Matrix][Channel_no].start_CFU();
			}
			
			System.out.println(Cfu_Array[3][Channel_no-1].register_array[4]);
			//enable the flag to write the results to the output.
			//Ram.write_output_flag = true;
			Ram.Write_Output(Cfu_Array[3][Channel_no-1].register_array[4]);
			
			System.out.println(Cfu_Array[7][Channel_no-1].register_array[4]);
			Ram.Write_Output(Cfu_Array[7][Channel_no-1].register_array[4]);
			
			System.out.println(Cfu_Array[3][Channel_no].register_array[4]);
			Ram.Write_Output(Cfu_Array[3][Channel_no-1].register_array[4]);
			
			System.out.println(Cfu_Array[7][Channel_no].register_array[4]);
			Ram.Write_Output(Cfu_Array[7][Channel_no-1].register_array[4]);
			
			//========================================================
		}

		for (int x = 0; x < no_cfu_row_int; x++) 
		{
			for (int y = 0; y < 2; y++) 
			{
				for (int i = 0; i < Cfu_Array[1][0].register_array.length; i++)
					System.out.println("CFU Array [" + x + "][" + y + "]: "
							+ "register[" + i + "]="
							+ Cfu_Array[x][y].register_array[i]);
			}
		}

	}

	@Override
	public void Get_Output() {
		// TODO Auto-generated method stub

	}
	public void Get_Statastics() {
		Form_Statistics_FIR13taps256samples.main(null);

	}
}